/**
 * ES6 模块的import命令可以加载 CommonJS 模块，但是只能整体加载，不能只加载单一的输出项。
 * 下面代码会报错
 * import { method } from 'commonjs-package'; ❌
 * 加载单一的输出项，可以写成下面这样。
 * import packageMain from 'commonjs-package'; ✔
 * const { method } = packageMain; ✔
 */

// process

// function isNodeEnvironment() {
//   return typeof global !== 'undefined' && global.process && global.process.version;
// }

// function isBrowserEnvironment() {
//   return typeof window !== 'undefined' && typeof window.document !== 'undefined';
// }

const simpleQuerystring = require('./simpleQuerystring');

module.exports = {
  querystring: require('./querystring'),
  Base64: require('./Base64'),
  MD5: require('./MD5'),
  /**
   * 深拷贝
   * @param {Array|Object} data 要深拷贝的数据
   * @param {Boolean} isSimple 是否简易模式 默认值：true
   * @returns 深拷贝后的数据
   */
  deepClone: require('./deepClone'),
  /**
   * 同步的延时事件
   * @param {Number} delay 要延迟的时间单位毫秒
   * @returns
   */
  sleep: require('./sleep'),
  /**
   * 获取数据类型
   * @param {any} data 数据
   * @returns {String} 数据类型
   */
  getDataType: require('./getDataType'),
  /**
   * 随机字符串
   * @param {Number} length 随机字符串长度 默认值：32
   * @returns {String} 字符串
   */
  randomString: require('./randomString'),
  /**
   * 文本去除空格
   * @param {String} value 要去除空格的文本
   * @param {Number} type 1-所有空格 2-前后空格 3-前空格 4-后空格 默认值：1 TRIM_TYPE: { ALL: 1, FRONT_REAR: 2, FRONT: 3, REAR: 4 }
   * @returns {String} 去除后的文本
   */
  trim: require('./trim'),
  /**
   * 获取url后面的传值
   * @param {String} url 网址地址或者一个query string数据
   * @returns {Object} 返回一个JSON数据
   */
  getQueryVariable: require('./getQueryVariable'),
  /**
   * 简单的字符串化查询字段仅支持单层Object数据
   * @param {Object} params 数据
   * @returns {String} 格式化好的数据
   */
  simpleQuerystring,
  /**
   * 数组去重
   * @param {Array} client 要去重的数据
   * @param {Function} rule 去重规则 默认值：JSON.stringify
   * @returns 去重后的结果
   */
  dedupe: require('./dedupe'),
  /**
   * 生成一个uuid
   * @param {Number} type 选择方法类型 传值为 UUID_TYPE: { NORMAL: 1, FAST: 2, COMPACT: 3 }
   * @returns {Function} 返回一个方法 注意：type为NORMAL时可以传值{ len = 32, radix = 16 }
   */
  UUID: require('./UUID'),
  /**
   * 下面的方法只有在浏览器中才能使用
   */
  browser: {
    /**
     * 下载流文件
     * @param {Blob} blob 流文件
     * @param {String} fileName 下载文件名 默认值：当前时间戳
     */
    downloadFile: function (blob, fileName = `${Date.now()}`) {
      if (typeof window === 'undefined') return false;
      const downloadElement = window.document.createElement('a');
      const href = window.URL.createObjectURL(blob); // 创建下载的链接
      downloadElement.href = href;
      downloadElement.download = fileName; // 下载后文件名
      window.document.body.appendChild(downloadElement);
      downloadElement.click(); // 点击下载
      window.document.body.removeChild(downloadElement); // 下载完成移除元素
      window.URL.revokeObjectURL(href); // 释放掉blob对象
    },
    /**
     * 复制文本
     * @param {String} text 要复制的文本
     * @returns 是否复制成功
     */
    copyText: function (text) {
      if (typeof window === 'undefined') return false;
      const input = window.document.createElement('input');
      window.document.body.appendChild(input);
      input.value = text; // 修改文本框的内容
      input.select(); // 选中文本
      const isSuccess = window.document.execCommand('copy'); // 执行浏览器复制命令
      window.document.body.removeChild(input);
      return isSuccess;
    },
    /**
     * 防抖
     * @param {Function} func 回调方法
     * @param {Number} wait 等待时间 默认值：1000毫秒
     * @param {Boolean} immediate 是否立即执行
     * @returns {Function} 返回一个方法
     */
    debounce: function (func = function () {}, wait = 1000, immediate = false) {
      if (typeof window === 'undefined') return false;
      let timer = null,
        result = null;
      return function (...args) {
        const _this = this;
        if (timer) clearTimeout(timer);
        if (immediate) {
          const callNow = !timer;
          if (callNow) {
            result = func.apply(_this, args);
          }
        }
        timer = setTimeout(function () {
          clearTimeout(timer);
          timer = null;
          result = func.apply(_this, args);
        }, wait);
        return result;
      };
    },
    /**
     * 节流
     * @param {Function} func 回调方法
     * @param {Number} wait 等待时间 默认值：300毫秒
     * @returns {Function} 返回一个方法
     */
    throttle: function (func = function () {}, wait = 300) {
      if (typeof window === 'undefined') return false;
      let lastTime = 0;
      return function (...args) {
        const _this = this;
        const now = Date.now();
        const coolingDown = now - lastTime < wait;
        if (coolingDown) {
          return;
        }
        lastTime = Date.now();
        func.apply(_this, args);
      };
    },
    /**
     *  jsonp访问接口方法 现在jsonp方法是给Promise对象可以用.then获取数据
     * @param {Object} options 传值
     * @param {String} options.url 接口地址
     * @param {String} options.jsonpCallback 自定义接口URL要拼接的名字 默认值: callback
     * @param {String} options.jsonp 自定义接口返回数据中的名字 无默认值
     * @param {Object} options.params 查询参数
     * @param {Function} options.callback 回调方法
     */
    jsonp: function ({
      url,
      params = {},
      jsonpCallback = 'callback',
      jsonp = '',
      callback = () => {}
    }) {
      return new Promise(resolve => {
        const callbackName =
          jsonp || `TaiShan_callback_${parseInt(Math.random() * 9999999999)}_${Date.now()}`;
        window[callbackName] = res => {
          callback(res);
          resolve(res);
        };
        params[jsonpCallback] = callbackName;
        // 创建 script 标签
        const script = window.document.createElement('script');
        script.src = `${url}?${simpleQuerystring(params)}`;
        script.defer = 'defer';
        function scriptOnload() {
          // 执行完成后删除script标签以及全局标签
          window.document.body.removeChild(script);
          if (Object.hasOwnProperty.call(window, callbackName)) {
            if (Reflect && Reflect.deleteProperty) {
              // Reflect.deleteProperty()
              // 允许用于删除对象上的属性,并且返回一个 Boolean 值表示该属性是否被成功删除。
              Reflect.deleteProperty(window, callbackName);
            } else {
              delete window[callbackName];
            }
          }
        }
        if (script.readyState) {
          // ie8及以下版本
          script.onreadystatechange = function () {
            if (script.readyState === 'complete' || script.readyState === 'loaded') {
              scriptOnload();
            }
          };
        } else {
          script.onload = scriptOnload;
        }
        window.document.body.appendChild(script);
      });
    },
    /**
     * 从URL到Blob对象,可以使用URL.createObjectURL生成临时URL
     * TIPS!!!注意此方法会跨域请在同一域名下操作
     * @param {Object} options 传值
     * @param {String} options.url url文件地址
     * @param {String} options.type 文件类型 默认值application/octet-stream
     * @returns {Promise} 返回一个Blob对象在Promise中
     */
    urlToBlob({ url, type = 'application/octet-stream' }) {
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('get', url, true);
        xhr.responseType = 'blob';
        xhr.onload = function (res) {
          if (this.status === 200) {
            resolve(new Blob([this.response], { type }));
          } else {
            reject(res);
          }
        };
        xhr.onerror = function (error) {
          reject(error);
        };
        xhr.send();
      });
    },
    /**
     * 从base64到Blob对象
     * @param {String} base64Data base64数据
     * @returns {Blob} 返回Blob对象
     */
    base64ToBlob(base64Data) {
      const mimeString = base64Data.split(';').shift().split(':').pop(); // mime类型
      const byteString = atob(base64Data.split(',').pop()); //base64 解码
      const arrayBuffer = new ArrayBuffer(byteString.length); //创建缓冲数组
      const intArray = new Uint8Array(arrayBuffer); //创建视图
      for (let i = 0; i < byteString.length; i++) {
        intArray[i] = byteString.charCodeAt(i);
      }
      return new Blob([intArray], { type: mimeString });
    }
  }
};
